<?php
namespace core;
//框架根目录
defined('CORE_PATH') or define('CORE_PATH',__DIR__);

//框架核心类
class Core{

    //配置内容
    protected $config = [];

    /**
     * 构造函数
     * 
     * 功能：
     * 加载配置信息
     */
    public function __construct($config) 
    {

        $this->config=$config;
    }

    /**
     * 启动web程序
     * 
     * 
     * 功能：
     * 进行 自动加载类
     * 检测 运行环境
     * 注销 全局变量
     * 加载 数据库配置
     * 开启 路由
     */
    public function run()
    {
        //进行 自动加载类
        spl_autoload_register(array($this,'loadClass'));
        
        //检测 运行环境
        $this->setReporting();


        //注销 全局变量
        $this->unregisterGlobals();

        //加载 数据库配置
        $this->setDbConfig();

        //开启 路由
        $this->route();

    }

    /**
     * 加载类
     */
    public function loadClass($className) 
    {
        $classMap = $this->classMap();
        //包含内核文件
        if(isset($classMap[$className])) {
            $file = $classMap[$className];
        }elseif (strpos($className, '\\') !== false) {
            // 包含应用（application目录）文件
            $file = APP_PATH . str_replace('\\', '/', $className) . '.php';
            if (!is_file($file)) {
                return;
            }
        } else {
            return;
        }
    
         include $file;
    }

    /**
     * 内核文件名称空间路径映射
     */
    public function classMap()
    {
        return [
            "core\db\Db" => CORE_PATH."/db/Db.php",
            "core\db\Sql" => CORE_PATH."/db/Sql.php",
            'core\base\Controller' => CORE_PATH . '/base/Controller.php',
            'core\base\Model' => CORE_PATH . '/base/Model.php',
            'core\base\View' => CORE_PATH . '/base/View.php',
        ];
    }

    /**
     * 检测运行环境
     */
    public function setReporting()
    {
        if (APP_DEBUG === true) {
            error_reporting(E_ALL);
            ini_set('display_errors','On');
        } else {
            error_reporting(E_ALL);
            ini_set('display_errors','Off');
            ini_set('log_errors', 'On');
        }
    }


    /**
     * 加载数据库配置
     */
    public function setDbConfig()
    {
        if ($this->config['db']) {

            define('DB_HOST', $this->config['db']['host']);
            define('DB_NAME', $this->config['db']['dbname']);
            define('DB_USER', $this->config['db']['username']);
            define('DB_PASS', $this->config['db']['password']);
        }
    }

        // 检测自定义全局变量并移除。因为 register_globals 已经弃用，如果
    // 已经弃用的 register_globals 指令被设置为 on，那么局部变量也将
    // 在脚本的全局作用域中可用。 例如， $_POST['foo'] 也将以 $foo 的
    // 形式存在，这样写是不好的实现，会影响代码中的其他变量。 相关信息，
    // 参考: http://php.net/manual/zh/faq.using.php#faq.register-globals
    public function unregisterGlobals()
    {
        if (ini_get('register_globals')) {
            $array = array('_SESSION', '_POST', '_GET', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES');
            foreach ($array as $value) {
                foreach ($GLOBALS[$value] as $key => $var) {
                    if ($var === $GLOBALS[$key]) {
                        unset($GLOBALS[$key]);
                    }
                }
            }
        }
    }

    /**
     * 路由类
     * 进行路由处理
     */
    public function route()
    {
        $controllerName = $this->config['defaultController'];
        $actionName = $this->config['defaultAction'];
        $param = array();

        $url = $_SERVER['REQUEST_URI'];

        //删除？之后的内容
        $position =  strpos($url,'?');
        $url = ($position === false) ? $url : substr($url, 0, $position);

        
        // 使得可以这样访问 index.php/{controller}/{action}
        $position = strpos($url, 'index.php');
        if ($position !== false) {
            $url = substr($url, $position + strlen('index.php'));
        }

        // 删除前后的“/”
        $url = trim($url, '/');

        if ($url) {
            // 使用“/”分割字符串，并保存在数组中
            $urlArray = explode('/', $url);
            // 删除空的数组元素
            $urlArray = array_filter($urlArray);
            
            // 获取控制器名
            $controllerName = ucfirst($urlArray[0]);
            
            // 获取动作名
            array_shift($urlArray);
            $actionName = $urlArray ? $urlArray[0] : $actionName;
            
            // 获取URL参数
            array_shift($urlArray);
            $param = $urlArray ? $urlArray : array();
        }

        // 判断控制器和操作是否存在
        $controller = 'app\\controllers\\'. $controllerName . 'Controller';
        if (!class_exists($controller)) {
            exit($controller . '控制器不存在1');
        }
        if (!method_exists($controller, $actionName)) {
            exit($actionName . '方法不存在');
        }

        // 如果控制器和操作名存在，则实例化控制器，因为控制器对象里面
        // 还会用到控制器名和操作名，所以实例化的时候把他们俩的名称也
        // 传进去。结合Controller基类一起看
        $dispatch = new $controller($controllerName, $actionName);

        // $dispatch保存控制器实例化后的对象，我们就可以调用它的方法，
        // 也可以像方法中传入参数，以下等同于：$dispatch->$actionName($param)
        call_user_func_array(array($dispatch, $actionName), $param);
    }

        // // 删除敏感字符
        // public function stripSlashesDeep($value)
        // {
        //     $value = is_array($value) ? array_map(array($this, 'stripSlashesDeep'), $value) : addslashes($value);
        //     return $value;
        // }
    
        // // 检测敏感字符并删除
        // public function removeMagicQuotes()
        // {
        //     $_GET = isset($_GET) ? $this->stripSlashesDeep($_GET ) : '';
        //     $_POST = isset($_POST) ? $this->stripSlashesDeep($_POST ) : '';
        //     $_COOKIE = isset($_COOKIE) ? $this->stripSlashesDeep($_COOKIE) : '';
        //     $_SESSION = isset($_SESSION) ? $this->stripSlashesDeep($_SESSION) : '';
        // }
}

// $config = require("../config/config.php");
// (new Core($config))->run();